home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / tran2d.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  41KB  |  1,582 lines

  1. /*
  2.  * $Id: tran2d.c,v 0.91 1994/02/20 00:53:14 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *   General 2D raster transformations: X'= M (X-S) where S is the
  26.  *   translational vector.
  27.  *
  28.  * We need this stuff because currently rotation is implemented this
  29.  * way. Once the three shear is implemented, general transformation
  30.  * will be of no use in bit program.
  31.  *
  32.  * Scaling is already implemented using different method.
  33.  *
  34.  */
  35.  
  36. #if !defined(lint) && defined(F_ID)
  37. char *id_tran = "$Id: tran2d.c,v 0.91 1994/02/20 00:53:14 zhao Pre-Release $";
  38. #endif
  39.  
  40. #include "bit.h"
  41. #include "dmalloc.h"
  42.  
  43. /******************** Local variables ***************************/
  44.  
  45. static int subpix;        /* if to do anti-aliasing */
  46. static int row, col, nrow, ncol;/* old the new size       */
  47.  
  48.  
  49. /*** input size and output size ****/
  50. static void
  51. set_tran_size(int oldrow, int oldcol, int newrow, int newcol)
  52. {
  53.     row = oldrow;
  54.     col = oldcol;
  55.     nrow = newrow;
  56.     ncol = newcol;
  57. }
  58.  
  59. /*** if subpixel sampling is desired ***/
  60. static void
  61. set_tran_subpix(int subp)
  62. {
  63.     subpix = subp;
  64. }
  65.  
  66. /****** pre-compute the x(column) transformations ********/
  67.  
  68. #define PRE_tran(prex, prey, func)                              \
  69.     do {                                                        \
  70.         int c_;                                                 \
  71.                                                                 \
  72.         prex = malloc(sizeof(float) * (ncol + 1));              \
  73.         prey = malloc(sizeof(float) * (ncol + 1));              \
  74.         if (!prex || !prey) {                                   \
  75.             Bark(func, "malloc failed");                        \
  76.             return -1;                                          \
  77.         }                                                       \
  78.         for (c_ = 0; c_ <= ncol; c_++) {                        \
  79.             prex[c_] = m[0][0] * (c_ - shift[0]);               \
  80.             prey[c_] = m[1][0] * (c_ - shift[0]);               \
  81.         }                                                       \
  82.     } while(ZERO)
  83.  
  84. #define POST_tran(prex, prey)                                   \
  85.        free(prex);                                              \
  86.        free(prey)
  87.  
  88. /*** check if transformed coodinates are outside image **********/
  89.  
  90. #define OutsideSRC(c,ir,ic) ((ir = (prey[c] + tmpy)) < 0 || ir >= row ||\
  91.                             ((ic = (prex[c] + tmpx)) < 0 || ic >= col))
  92.  
  93. /***************************************************************
  94.  *  transform a colorindex based raster image
  95.  ****************************************************************/
  96. static int
  97. tran2d_ci(ci_t **in, ci_t **out,
  98.       float m[][2], float shift[], ci_t fill)
  99. {
  100.     register ci_t *ras = out[0];
  101.     register float *prex, *prey, tmpy, tmpx;
  102.     register int c, ic, ir, r;
  103.     long rlines;
  104.  
  105.     PRE_tran(prex, prey, "tran2d_ci");
  106.     rlines = progress_report("Tran2D_ci ...", nrow);
  107.  
  108.     for (r = 0; r < nrow; r++)
  109.       {
  110.       REPORT(r, rlines);
  111.       tmpx = m[0][1] * (r - shift[1]) + 0.1;
  112.       tmpy = m[1][1] * (r - shift[1]) + 0.1;
  113.       for (c = 0; c < ncol; c++, ras++)
  114.           *ras = OutsideSRC(c, ir, ic) ? fill : in[ir][ic];
  115.       }
  116.     POST_tran(prex, prey);
  117.     remove_progress_report();
  118.     return 0;
  119. }
  120.  
  121. /*************************************************************
  122.  * Transform a packed pixel based image
  123.  *************************************************************/
  124. static int
  125. tran2d_cpack(rgba_t **in, rgba_t **out, float m[][2],
  126.          float shift[], rgba_t fill)
  127. {
  128.     register rgba_t *ras = out[0];
  129.     register float *prex, *prey, tmpy, tmpx;
  130.     register int c, ic, ir, r;
  131.     long rlines;
  132.  
  133.     PRE_tran(prex, prey, "tran2d_cpack");
  134.     rlines = progress_report("Tran2D_cpack ...", nrow);
  135.  
  136.     for (r = 0; r < nrow; r++)
  137.       {
  138.       REPORT(r, rlines);
  139.       tmpx = m[0][1] * (r - shift[1]) + 0.5;
  140.       tmpy = m[1][1] * (r - shift[1]) + 0.5;
  141.       for (c = 0; c < ncol; c++, ras++)
  142.           *ras = OutsideSRC(c, ir, ic) ? fill : in[ir][ic];
  143.       }
  144.     POST_tran(prex, prey);
  145.     remove_progress_report();
  146.     return 0;
  147. }
  148.  
  149. /*********************************************************************
  150.  * Interpolate at (x,y) given in[1-3]. minimum x and y should not be
  151.  * smaller than -1 and maximum x and y should not be greater than col
  152.  * and row.
  153.  ********************************************************************/
  154. static void
  155. frac(pc_t *po1, pc_t **in1, pc_t *po2, pc_t **in2,
  156.      pc_t *po3, pc_t **in3, float x, float y, int fill[])
  157. {
  158.     float pdx[4], pdy[4], pdxy[4], ff[4], dx, dy, dxy;
  159.     float f00[4], f01[4], f10[4], f11[4];
  160.     int i, ix1, ix2, iy1, iy2;
  161.  
  162.     ix1 = (x < 0.0) ? -1 : x;
  163.     iy1 = (y < 0.0) ? -1 : y;
  164.     ix2 = ix1 + 1;
  165.     iy2 = iy1 + 1;
  166.  
  167.     i = (iy1 >= 0 && ix1 >= 0);
  168.     f00[1] = i ? in1[iy1][ix1] : fill[0];
  169.     f00[2] = i ? in2[iy1][ix1] : fill[1];
  170.     f00[3] = i ? in3[iy1][ix1] : fill[2];
  171.  
  172.     i = (iy1 >= 0 && ix2 < col);
  173.     f01[1] = i ? in1[iy1][ix2] : fill[0];
  174.     f01[2] = i ? in2[iy1][ix2] : fill[1];
  175.     f01[3] = i ? in3[iy1][ix2] : fill[2];
  176.  
  177.     i = (iy2 < row && ix1 >= 0);
  178.     f10[1] = i ? in1[iy2][ix1] : fill[0];
  179.     f10[2] = i ? in2[iy2][ix1] : fill[1];
  180.     f10[3] = i ? in3[iy2][ix1] : fill[2];
  181.  
  182.     i = (iy2 < row && ix2 < col);
  183.     f11[1] = i ? in1[iy2][ix2] : fill[0];
  184.     f11[2] = i ? in2[iy2][ix2] : fill[1];
  185.     f11[3] = i ? in3[iy2][ix2] : fill[2];
  186.  
  187.     dx = x - ix1;
  188.     dy = y - iy1;
  189.     dxy = dx * dy;
  190.  
  191.     for (i = 1; i <= 3; i++)
  192.       {
  193.       pdx[i] = f01[i] - f00[i];
  194.       pdy[i] = f10[i] - f00[i];
  195.       pdxy[i] = f11[i] - f00[i];
  196.       ff[i] = f00[i] + dx * pdx[i] + dy * pdy[i] +
  197.           0.5 * dxy * (pdxy[i] - pdx[i] - pdy[i]) + 0.7;
  198.       if (ff[i] >= PCMAX)
  199.           ff[i] = PCMAX - 1;
  200.       if (ff[i] < 0.0)
  201.           ff[i] = 0.0;
  202.       }
  203.     *po1 = ff[1];
  204.     *po2 = ff[2];
  205.     *po3 = ff[3];
  206. }
  207.  
  208. /*****************************************************************
  209.  * Apply the transfomration matrix M and shift vector M to
  210.  * R,G,B simultaneously with subpixel sampling taking care of
  211.  ****************************************************************/
  212. #if 1
  213. static int
  214. tran2d_rgb(pc_t **in[], pc_t **out[],
  215.        float m[][2], float shift[], int fill[3])
  216. {
  217.     register float *prex, *prey, tmpy, tmpx;
  218.     register pc_t *ras1 = out[0][0], *ras2 = out[1][0], *ras3 = out[2][0];
  219.     register pc_t **in1 = in[0], **in2 = in[1], **in3 = in[2];
  220.     register int c, ic, ir;
  221.     int r;
  222.     long rlines;
  223.  
  224.     PRE_tran(prex, prey, "Tran2dRGB");
  225.     rlines = progress_report("Tran2D_RGB ...", nrow);
  226.  
  227.     for (r = 0; r < nrow; r++)
  228.       {
  229.       REPORT(r, rlines);
  230.       if (!subpix)
  231.         {
  232.         tmpx = m[0][1] * (r - shift[1]) + 0.5;
  233.         tmpy = m[1][1] * (r - shift[1]) + 0.5;
  234.         for (c = 0; c < ncol; c++, ras1++, ras2++, ras3++)
  235.           {
  236.               if (OutsideSRC(c, ir, ic))
  237.             {
  238.                 *ras1 = fill[0];
  239.                 *ras2 = fill[1];
  240.                 *ras3 = fill[2];
  241.             }
  242.               else
  243.             {
  244.                 *ras1 = in1[ir][ic];
  245.                 *ras2 = in2[ir][ic];
  246.                 *ras3 = in3[ir][ic];
  247.             }
  248.           }
  249.         }
  250.       else
  251.         {
  252.         register float dr, dc;
  253.         tmpx = m[0][1] * (r - shift[1]) + 0.2;
  254.         tmpy = m[1][1] * (r - shift[1]) + 0.2;
  255.         for (c = 0; c < ncol; c++, ras1++, ras2++, ras3++)
  256.           {
  257.               dr = (tmpy + prey[c]);
  258.               dc = (tmpx + prex[c]);
  259.               if (dr < -1.0 || dr > row || dc < -1.0 || dc > col)
  260.             {
  261.                 *ras1 = fill[0];
  262.                 *ras2 = fill[1];
  263.                 *ras3 = fill[2];
  264.             }
  265.               else
  266.             {
  267.                 frac(ras1, in1, ras2, in2, ras3, in3, dc, dr, fill);
  268.             }
  269.           }
  270.         }
  271.       }
  272.     POST_tran(prex, prey);
  273.     remove_progress_report();
  274.     return 0;
  275. }
  276.  
  277. #else
  278. static void
  279. weight(pc_t *po1, pc_t **in1, pc_t *po2, pc_t **in2,
  280.        pc_t *po3, pc_t **in3, float x[], float y[])
  281. {
  282.     register int ix, iy;
  283.     register float h, w, sum1, sum2, sum3, area;
  284.  
  285.     sum1 = sum2 = sum3 = area = 0.0;
  286.     for (iy = y[0]; iy <= y[1]; iy++)
  287.       {
  288.       if (iy < y[0])
  289.           h = (float) iy + 1.0 - y[0];
  290.       else if ((float) iy + 1.0 > y[1])
  291.           h = y[1] - iy;
  292.       else
  293.           h = 1.0;
  294.  
  295.       for (ix = x[0]; ix <= x[1]; ix++)
  296.         {
  297.         if (ix < x[0])
  298.             w = (float) ix + 1.0 - x[0];
  299.         else if ((float) ix + 1.0 > x[1])
  300.             w = x[1] - ix;
  301.         else
  302.             w = 1.0;
  303.         sum1 += (float) in1[iy][ix] * (h * w);
  304.         sum2 += (float) in2[iy][ix] * (h * w);
  305.         sum3 += (float) in3[iy][ix] * (h * w);
  306.         area += (h * w);
  307.         }
  308.       }
  309.     sum1 /= area;
  310.     sum2 /= area;
  311.     sum3 /= area;
  312.     if (sum1 >= PCMAX)
  313.     sum1 = PCMAX - 1;
  314.     if (sum2 >= PCMAX)
  315.     sum2 = PCMAX - 1;
  316.     if (sum3 >= PCMAX)
  317.     sum3 = PCMAX - 1;
  318.     if (sum1 < 0.0)
  319.     sum1 = 0.0;
  320.     if (sum2 < 0.0)
  321.     sum2 = 0.0;
  322.     if (sum3 < 0.0)
  323.     sum3 = 0.0;
  324.     *po1 = (0.5 + sum1);
  325.     *po2 = (0.5 + sum2);
  326.     *po3 = (0.5 + sum3);
  327. }
  328.  
  329. /*
  330.  * the transformation routine for seperate RGB's
  331.  */
  332. static int
  333. tran2d_rgb(pc_t **in[], pc_t **out[],
  334.        const float m[][2], const float shift[], int fill[3])
  335. {
  336.     register float *prex, *prey, tmpy, tmpx;
  337.     register pc_t *ras1 = out[0][0], *ras2 = out[1][0], *ras3 = out[2][0];
  338.     register pc_t **in1 = in[0], **in2 = in[1];
  339.     **in3 = in[2];
  340.     register int c, ic, ir;
  341.     int r;
  342.     long rlines;
  343.  
  344.     PRE_tran(prex, prey, "Tran2dRGB");
  345.     rlines = progress_report("Tran2D_RGB ...", nrow);
  346.  
  347.     for (r = 0; r < nrow; r++)
  348.       {
  349.       REPORT(r, rlines);
  350.       if (!subpix)
  351.         {
  352.         tmpx = m[0][1] * (r - shift[1]) + 0.5;
  353.         tmpy = m[1][1] * (r - shift[1]) + 0.5;
  354.         for (c = 0; c < ncol; c++, ras1++, ras2++, ras3++)
  355.           {
  356.               if (OutsideSRC(c, ir, ic))
  357.             {
  358.                 *ras1 = fill[0];
  359.                 *ras2 = fill[1];
  360.                 *ras3 = fill[2];
  361.             }
  362.               else
  363.             {
  364.                 *ras1 = in1[ir][ic];
  365.                 *ras2 = in2[ir][ic];
  366.                 *ras3 = in3[ir][ic];
  367.             }
  368.           }
  369.         }
  370.       else
  371.         {
  372.         register float dr, dc;
  373.         tmpx = m[0][1] * (r - shift[1]);
  374.         tmpy = m[1][1] * (r - shift[1]);
  375.         for (c = 0; c < ncol; c++, ras1++, ras2++, ras3++)
  376.           {
  377.               dr = (tmpy + prey[c]);
  378.               dc = (tmpx + prex[c]);
  379.               if (dr < -1.0 || dr > row || dc < -1.0 || dc > col)
  380.             {
  381.                 *ras1 = fill[0];
  382.                 *ras2 = fill[1];
  383.                 *ras3 = fill[2];
  384.             }
  385.               else
  386.             {
  387.                 weight(ras1, in1, ras2, in2, ras3, in3, dc, dr, fill);
  388.             }
  389.           }
  390.         }
  391.       }
  392.     POST_tran(prex, prey);
  393.     remove_progress_report();
  394.     return 0;
  395. }
  396.  
  397. #endif
  398.  
  399. /*****************************************************************
  400.  * Transform a primary color matrix
  401.  ****************************************************************/
  402. static int
  403. tran2d_pc(pc_t **in1, pc_t **out1,
  404.       float m[][2], float shift[], int fill)
  405. {
  406.     register float *prex, *prey, tmpy, tmpx;
  407.     register pc_t *ras1 = out1[0];
  408.     register int c, ic, ir;
  409.     int r;
  410.     long rlines;
  411.  
  412.     PRE_tran(prex, prey, "Tran2dRGB");
  413.     rlines = progress_report("Tran2D_PC ...", nrow);
  414.  
  415.     for (r = 0; r < nrow; r++)
  416.       {
  417.       REPORT(r, rlines);
  418.       if (!subpix)
  419.         {
  420.         tmpx = m[0][1] * (r - shift[1]) + 0.5;
  421.         tmpy = m[1][1] * (r - shift[1]) + 0.5;
  422.         for (c = 0; c < ncol; c++, ras1++)
  423.             *ras1 = OutsideSRC(c, ir, ic) ? fill : in1[ir][ic];
  424.         }
  425.       else
  426.         {
  427.         register float dr, dc, drc;
  428.         register int ir1, ic1;
  429.  
  430.         tmpx = m[0][1] * (r - shift[1]);
  431.         tmpy = m[1][1] * (r - shift[1]);
  432.         for (c = 0; c < ncol; c++, ras1++)
  433.           {
  434.               ir = (0.2 + (dr = (tmpy + prey[c])));
  435.               ic = (0.2 + (dc = (tmpx + prex[c])));
  436.               dr = dr - ir;
  437.               dc = dc - ic;
  438.               if (dr < 0.0)
  439.             {
  440.                 dr = dr + 1.0;
  441.                 ir--;
  442.             }
  443.               if (dc < 0.0)
  444.             {
  445.                 dc = dc + 1.0;
  446.                 ic--;
  447.             }
  448.               if (ir < 0 || ir >= row || ic < 0 || ic >= col)
  449.             {
  450.                 *ras1 = fill;
  451.             }
  452.               else
  453.             {
  454.                 drc = dr * dc;
  455.                 ir1 = ir + (ir < row - 1);
  456.                 ic1 = ic + (ic < col - 1);
  457.                 GETFRAC(*ras1, ir, ic, ir1, ic1, dr, dc, drc, in1, 0, PCMAX - 1);
  458.             }
  459.           }
  460.         }
  461.       }
  462.     POST_tran(prex, prey);
  463.     remove_progress_report();
  464.     return 0;
  465. }
  466.  
  467. /*****************************************************************
  468.  * global interface for 2D raster transformations. Note that fill color
  469.  * could be either in RGBA format or just an index depending on the
  470.  * image type
  471.  ******************************************************************/
  472.  
  473. int
  474. img_tran(IPTR im, int nh, int nw, float m[][2], float shift[],
  475.      rgba_t fill, int subp)
  476. {
  477.     pc_t **pcm[3];
  478.     void *rm;
  479.     int status, fc[3];
  480.  
  481.     set_tran_size(im->h, im->w, nh, nw);
  482.     set_tran_subpix(subp);
  483.  
  484.     if (!subp)
  485.       {                /* simple transformation */
  486.       rm = get_mat(nh, nw, im->esize);
  487.       status = IS_CI(im) ? tran2d_ci(im->mraster, rm, m, shift, fill) :
  488.           tran2d_cpack(im->mraster, rm, m, shift, fill);
  489.       if (status >= 0)
  490.           fill_image_struct(im, rm, nh, nw, im->type);
  491.       return status;
  492.       }
  493.  
  494.     /* with subpixel sampling */
  495.  
  496.     if (img_get_rgb(im) < 0)
  497.     return -1;
  498.  
  499. #ifdef TIGHT_MEM
  500.     if (im->size > MAXMEMK)
  501.     img_free_rastermem(im);
  502. #endif
  503.  
  504.     if (IS_CI(im))
  505.       {
  506.       get_cmap_entry(im->cmap, fc, fill);
  507.       fill = RGB2CPACK(fc[0], fc[1], fc[2]);
  508.       }
  509.     else
  510.       {
  511.       CPACK2RGB(fill, fc[0], fc[1], fc[2]);
  512.       }
  513.  
  514.     if (IS_GRAY(im))
  515.       {
  516.       if (!(pcm[0] = pcm[1] = pcm[2] = get_mat(nh, nw, sizeof(pc_t))))
  517.             return -1;
  518.       }
  519.     else
  520.       {
  521.       if (!(pcm[0] = get_mat(nh, nw, sizeof(pc_t))) ||
  522.           ! (pcm[1] = get_mat(nh, nw, sizeof(pc_t))) ||
  523.           ! (pcm[2] = get_mat(nh, nw, sizeof(pc_t))))
  524.             return -1;
  525.       }
  526.  
  527.     status = IS_GRAY(im) ?
  528.     tran2d_pc(im->pc[0], pcm[0], m, shift, fc[0]) :
  529.     tran2d_rgb(im->pc, pcm, m, shift, fc);
  530.  
  531.     if (status >= 0)
  532.       {
  533.       im->w = nw;
  534.       im->h = nh;
  535.       img_replace_rgb(im, pcm[0], pcm[1], pcm[2]);
  536.       img_rgb_to_cpack(im);
  537.       img_free_rgbmem(im);
  538.       }
  539.     return status;
  540. }
  541.  
  542. /****************************************************************
  543.  * Scaling an image.
  544.  ************************************************************{***/
  545.  
  546. /*********************************************************
  547.  * Scale without subpixel sampling
  548.  ********************************************************/
  549. static int
  550. scale_simple(IPTR im, int nh, int nw)
  551. {
  552.     void *nm, *om = im->mraster;
  553.     double xfac = (double) im->w / nw, yfac = (double) im->h / nh;
  554.     int *lut, j, jj;
  555.     long rlines;
  556.  
  557.  
  558.     /* generate a lookup table */
  559.     if (!(lut = malloc(sizeof(int) * (nw + 1))))
  560.       return -1;
  561.     if (!(nm = get_mat(nh, nw, im->esize)))
  562.     return -1;
  563.  
  564.     rlines = progress_report("Scale(Simple) ...", nh);
  565.     for (j = 0; j < nw; j++)
  566.     lut[j] = (xfac * j + 0.001);
  567.  
  568.     if (IS_CI(im))
  569.       {
  570.       register ci_t *nrows, *orows;
  571.       register int i;
  572.       for (j = 0; j < nh; j++)
  573.         {
  574.         jj = (yfac * j + 0.001);
  575.         REPORT(j, rlines);
  576.         nrows = ((ci_t **) nm)[j];
  577.         orows = ((ci_t **) om)[jj];
  578.         for (i = 0; i < nw; i++)
  579.           {
  580.               *(nrows + i) = *(orows + lut[i]);
  581.           }
  582.         }
  583.       }
  584.     else
  585.       {
  586.       register rgba_t *nrows, *orows;
  587.       register int i;
  588.       for (j = 0; j < nh; j++)
  589.         {
  590.         REPORT(j, rlines);
  591.         jj = (yfac * j + 0.001);
  592.         nrows = ((rgba_t **) nm)[j];
  593.         orows = ((rgba_t **) om)[jj];
  594.         for (i = 0; i < nw; i++)
  595.           {
  596.               *(nrows + i) = *(orows + lut[i]);
  597.           }
  598.         }
  599.       }
  600.     free(lut);
  601.     remove_progress_report();
  602.     return fill_image_struct(im, nm, nh, nw, im->type);
  603. }
  604.  
  605.  
  606.  
  607. /*********************************************************************
  608.  * Blend the adjucent pixels, good for scaling factors between 0.5 and 2.0.
  609.  * Grayscale images are handled same as color images memoerywise,
  610.  * but faster.
  611.  *********************************************************************/
  612.  
  613. static int
  614. scale_blend(pc_t **om[], pc_t **nm[],
  615.         int h, int w, int nh, int nw, int comp)
  616. {
  617.     double xs = (double) nw / w, ys = (double) nh / h, off;
  618.     int *lut, *buf[3];
  619.     int i, j, ii, jj, ii1;
  620.     long rlines;
  621.     register float fi, *flut;
  622.     register pc_t *r1, *g1, *b1;
  623.     register pc_t *r2, *g2, *b2;
  624.  
  625.     rlines = progress_report("Scaling(Fast) ...", nh);
  626.  
  627.     lut = malloc(sizeof(int) * (nw + 1));
  628.     flut = malloc(sizeof(float) * (nw + 1));
  629.  
  630.     /* offset is critical for high frequency data */
  631.     off = (1.0 - xs);
  632.     for (i = 0; i < nw; i++)
  633.       {
  634.       flut[i] = (double) i / xs + off;
  635.       if (flut[i] < 0.0)
  636.           flut[i] = 0.0;
  637.       lut[i] = flut[i];
  638.       flut[i] = flut[i] - lut[i];
  639.       }
  640.  
  641.     /* now do it */
  642.  
  643.     /* get the buffers */
  644.     for (i = 0; i < 3; i++)
  645.     buf[i] = malloc(sizeof(int) * (w + 2));
  646.  
  647.  
  648.     off = (1.0 - ys);
  649.     for (j = 0; j < nh; j++)
  650.       {
  651.       fi = (double) j / ys + off;
  652.       if (fi < 0.0)
  653.           fi = 0.0;
  654.       jj = fi;
  655.       fi = fi - jj;
  656.       REPORT(j, rlines);
  657.  
  658.       r1 = om[0][jj];
  659.       r2 = om[0][jj + (jj < (h - 1))];
  660.  
  661.       if (comp == 1)
  662.         {            /* gray images */
  663.         for (i = 0; i < w; i++, r1++, r2++)
  664.           {
  665.               buf[0][i] = buf[1][i] = buf[2][i] =
  666.               (Lintp((int) *r1, (int) *r2, fi) + 0.5);
  667.           }
  668.         }
  669.       else
  670.         {            /* color image */
  671.         g1 = om[1][jj];
  672.         b1 = om[2][jj];
  673.         g2 = om[1][jj + (jj < (h - 1))];
  674.         b2 = om[2][jj + (jj < (h - 1))];
  675.         /* make a new row */
  676.         for (i = 0; i < w; i++, r1++, g1++, b1++, r2++, g2++, b2++)
  677.           {
  678.               buf[0][i] = (Lintp((int) *r1, (int) *r2, fi) + 0.5);
  679.               buf[1][i] = (Lintp((int) *g1, (int) *g2, fi) + 0.5);
  680.               buf[2][i] = (Lintp((int) *b1, (int) *b2, fi) + 0.5);
  681.           }
  682.         }
  683.  
  684.  
  685.       buf[0][w] = buf[0][w - 1];
  686.       buf[1][w] = buf[1][w - 1];
  687.       buf[2][w] = buf[2][w - 1];
  688.  
  689.       r1 = nm[0][j];
  690.       g1 = nm[1][j];
  691.       b1 = nm[2][j];
  692.  
  693.       /* scale x */
  694.  
  695.       if (comp == 1)
  696.         {
  697.         for (i = 0; i < nw; i++, r1++, g1++, b1++)
  698.           {
  699.               ii = lut[i];
  700.               fi = flut[i];
  701.               ii1 = ii + 1;
  702.               *r1 = *g1 = *b1 =
  703.               (Lintp(buf[0][ii], buf[0][ii1], fi) + 0.5);
  704.           }
  705.         }
  706.       else
  707.         {
  708.         for (i = 0; i < nw; i++, r1++, g1++, b1++)
  709.           {
  710.               ii = lut[i];
  711.               fi = flut[i];
  712.               ii1 = ii + 1;
  713.               *r1 = (Lintp(buf[0][ii], buf[0][ii1], fi) + 0.5);
  714.               *g1 = (Lintp(buf[1][ii], buf[1][ii1], fi) + 0.5);
  715.               *b1 = (Lintp(buf[2][ii], buf[2][ii1], fi) + 0.5);
  716.           }
  717.         }
  718.  
  719.       }
  720.     free(lut);
  721.     free(flut);
  722.     free(buf[0]);
  723.     free(buf[1]);
  724.     free(buf[2]);
  725.     remove_progress_report();
  726.     return 0;
  727. }
  728.  
  729. /**********************************************************************
  730.  * Scaling with proper averaging: Slow, but results are good. For some
  731.  * reason, better than PNMSCALE with high frequency data
  732.  ***********************************************************************/
  733. static int
  734. scale_proper(pc_t **om[], pc_t **nm[],
  735.          int h, int w, int nh, int nw, int comp)
  736. {
  737.     float xt = (double) w / nw;
  738.     float yt = (double) h / nh;
  739.     float s1, s2, s3, area, delta;
  740.     float width, height;
  741.     float x1, x2, y1, y2;
  742.     int x, y, i, j;
  743.     long rlines;
  744.  
  745.  
  746.     rlines = progress_report("Scale(HiFi) ...", nh);
  747.  
  748.     for (y1 = 0.0, j = 0; j < nh; j++, y1 += yt)
  749.       {
  750.       y2 = y1 + yt;
  751.       if (y2 > h)
  752.           y2 = h;
  753.       REPORT(j, rlines);
  754.       for (x1 = 0.0, i = 0; i < nw; i++, x1 += xt)
  755.         {
  756.         s1 = s2 = s3 = area = 0.0;
  757.         x2 = x1 + xt;
  758.         if (x2 > w)
  759.             x2 = w;
  760.         for (y = (int) y1; y < y2; y++)
  761.           {
  762.               if (y < y1)
  763.               height = y + 1.0 - y1;
  764.               else if ((y + 1.0) > y2)
  765.               height = y2 - y;
  766.               else
  767.               height = 1.0;
  768.  
  769.               for (x = (int) x1; x < x2; x++)
  770.             {
  771.                 if (x < x1)
  772.                 width = x + 1.0 - x1;
  773.                 else if ((x + 1.0) > x2)
  774.                 width = x2 - x;
  775.                 else
  776.                 width = 1.0;
  777.                 area += (delta = width * height);
  778.  
  779.                 s1 += delta * om[0][y][x];
  780.                 if (comp == 1)
  781.                   {
  782.                   s2 = s3 = s1;
  783.                   }
  784.                 else
  785.                   {
  786.                   s2 += delta * om[1][y][x];
  787.                   s3 += delta * om[2][y][x];
  788.                   }
  789.             }
  790.           }
  791.         nm[0][j][i] = (s1 / area);
  792.         nm[1][j][i] = (s2 / area);
  793.         nm[2][j][i] = (s3 / area);
  794.         }
  795.       }
  796.     remove_progress_report();
  797.     return 0;
  798. }
  799.  
  800.  
  801. /*************************************************************
  802.  * SCALING dispatcher. All types.
  803.  * If magnification with integer factor, no subpixel applies.
  804.  * If shrinking with factor greater than 0.5, use simple blending
  805.  * else do box average.
  806.  ************************************************************/
  807. int
  808. img_scale(IPTR im, int nh, int nw, int subp, int fit, rgba_t fill)
  809. {
  810.     float m[2][2], shift[2];
  811.     double xs, ys, ts;
  812.     int ss[2], err, i;
  813.     pc_t **nm[3];
  814.  
  815.  
  816.     xs = (double) im->w / nw;
  817.     ys = (double) im->h / nh;
  818.  
  819.     /* if fitting is requested with equal scaling, disable it */
  820.     if (fit && (Abs(xs - ys) < 0.00001))
  821.       {
  822.       fit = 0;
  823.       M_info("Scale", "Disabling fit");
  824.       }
  825.  
  826.     /* fit feature is uniq, can't be handled by scaling alone */
  827.     if (fit)
  828.       {
  829.       ts = (xs < ys) ? ys : xs;
  830.       ss[1] = (((double) nh - im->h / ts + 0.2)) / 2;
  831.       ss[0] = (((double) nw - im->w / ts + 0.2)) / 2;
  832.       xs = ys = ts;
  833.       shift[0] = ss[0];
  834.       shift[1] = ss[1];
  835.  
  836.       /* get the transformation matrix */
  837.       m[0][0] = xs;
  838.       m[1][1] = ys;
  839.       m[0][1] = m[1][0] = 0.0;
  840.       err = img_tran(im, nh, nw, m, shift, fill, subp) < 0;
  841.       }
  842.  
  843.     /*
  844.      * if no subpixel sampling requested, or magnification with integer
  845.      * factors, use pixel replication
  846.      */
  847.  
  848.     else if (!subp || ((nw % im->w) == 0 && (nh % im->h) == 0))
  849.       {
  850.       err = scale_simple(im, nh, nw);
  851.       }
  852.     else
  853.       {                /* anti-aliasing */
  854.       if (img_get_rgb(im) < 0)
  855.           return -1;
  856.  
  857. #ifdef TIGHT_MEM
  858.       if (im->size > MAXMEMK)
  859.           img_free_rastermem(im);
  860. #endif
  861.  
  862.       for (i = err = 0; !err && i < 3; i++)
  863.           err = (!(nm[i] = get_mat(nh, nw, sizeof(pc_t))));
  864.  
  865.       err = err || ((subp < 2) ? scale_blend : scale_proper)
  866.           (im->pc, nm, im->h, im->w, nh, nw, IS_GRAY(im));
  867.  
  868.       if (err)
  869.           return -1;
  870.       im->w = nw;
  871.       im->h = nh;
  872.       img_replace_rgb(im, nm[0], nm[1], nm[2]);
  873.       img_rgb_to_cpack(im);
  874.       img_free_rgbmem(im);
  875.       }
  876.     return err;
  877. }
  878.  
  879. /******************************************************************
  880.  * GUI part of scaling
  881.  *****************************************************************/
  882. static double xscale, yscale;    /* current scale    */
  883. static double xsize, ysize;    /* current size     */
  884. static int fillcol[4];        /* fill color       */
  885.  
  886. static int showsize;        /* reporint control */
  887. static int subp = 1, exact, keepasp = 1;
  888. static int ch, cw, minw;
  889. static void create_form_fscale(void);
  890.  
  891. #define MAXSC    10.0        /* maximum scale factor       */
  892. #define MINSC    0.01        /* minimum scale factor       */
  893.  
  894. static FL_FORM *fscale;
  895. static FL_OBJECT *xcnt, *ycnt, *scaleit, *scaledone;
  896. static FL_OBJECT *ssubp[3];
  897.  
  898. static void
  899. new_size(IPTR im)
  900. {
  901.     int sh, sw;
  902.  
  903.     ysize = ch = im->h;
  904.     xsize = cw = im->w;
  905.     xscale = yscale = 1.0;
  906.     sh = (MINSC * ch);
  907.     sw = (MINSC * cw);
  908.     /* round it down to nice numbers */
  909.     minw = (sh > sw) ? sw : sh;
  910.     SET_NICE(minw);
  911. }
  912.  
  913. /***** Set current scaling factors or scaled size ******/
  914. static void
  915. set_counter(void)
  916. {
  917.  
  918.     fl_freeze_form(fscale);
  919.     if (showsize)
  920.       {
  921.       fl_set_counter_value(xcnt, xsize);
  922.       fl_set_counter_value(ycnt, ysize);
  923.       }
  924.     else
  925.       {
  926.       fl_set_counter_value(xcnt, xscale);
  927.       fl_set_counter_value(ycnt, yscale);
  928.       }
  929.     fl_unfreeze_form(fscale);
  930. }
  931.  
  932. /********* Show current scaling factors or scaled size *********/
  933. /* ARGSUSED */
  934. static void
  935. show_size(FL_OBJECT * ob, long p)
  936. {
  937.     fl_freeze_form(fscale);
  938.     if ((showsize = p))
  939.       {
  940.       fl_set_counter_precision(xcnt, 0);
  941.       fl_set_counter_bounds(xcnt, minw, MAXSC * cw);
  942.       fl_set_counter_precision(ycnt, 0);
  943.       fl_set_counter_bounds(ycnt, minw, MAXSC * ch);
  944.       fl_set_counter_step(xcnt, minw, 5 * minw);
  945.       fl_set_counter_step(ycnt, minw, 5 * minw);
  946.       }
  947.     else
  948.       {
  949.       fl_set_counter_precision(xcnt, 2);
  950.       fl_set_counter_precision(ycnt, 2);
  951.       fl_set_counter_bounds(xcnt, MINSC, MAXSC);
  952.       fl_set_counter_bounds(ycnt, MINSC, MAXSC);
  953.       fl_set_counter_step(xcnt, MINSC, 10 * MINSC);
  954.       fl_set_counter_step(ycnt, MINSC, 10 * MINSC);
  955.       }
  956.     set_counter();
  957.     fl_unfreeze_form(fscale);
  958. }
  959.  
  960. /*****************************************************************
  961.  * this one is called from the control panel. Return negative value
  962.  * to indicate failure and suppress redraw in driver
  963.  *******************************************************************/
  964. int
  965. do_scale(IPTR im)
  966. {
  967.     FL_OBJECT *ret;
  968.     short val;
  969.     int status = 0, ncols, nrows;
  970.     int changed = 0;
  971.  
  972.     create_form_fscale();
  973.  
  974.     /* For BW images, set default to no subpixel */
  975.     if (IS_BW(im))
  976.       {
  977.       subp = 0;
  978.       fl_set_button(ssubp[0], subp == 0);
  979.       fl_set_button(ssubp[1], subp == 1);
  980.       fl_set_button(ssubp[2], subp == 2);
  981.       }
  982.  
  983.     new_size(im);
  984.     show_size(0, showsize);
  985.  
  986.     bit_show_form(fscale, FL_PLACE_MOUSE, 0, "Scale");
  987.  
  988.     while (status >= 0 && (ret = fl_do_forms()) != scaledone)
  989.       {
  990.       if (ret == FL_EVENT)
  991.           (void) bit_qread(&val);
  992.       else if (ret == scaleit)
  993.         {
  994.         ncols = (0.6 + xsize);
  995.         nrows = (0.6 + ysize);
  996.         if (nrows == im->h && ncols == im->w)
  997.             continue;
  998.         changed = 1;
  999.         show_busy("");
  1000.         status = img_scale(im, nrows, ncols, subp, exact,
  1001.                    IS_CI(im) ? fillcol[3] :
  1002.                    Pack(fillcol[0], fillcol[1], fillcol[2]));
  1003.         end_busy();
  1004.         if (status >= 0)
  1005.             im->io->display(im, -1, 0);
  1006.         new_size(im);
  1007.         show_size(0, showsize);
  1008.         }
  1009.       }
  1010.     bit_hide_form(fscale);
  1011.     return (status >= 0 && changed) ? 0 : -1;
  1012. }
  1013.  
  1014. /*
  1015.  * call back routine if there is changes in counter. note that set_counter
  1016.  * must be called if aspect is to be kept
  1017.  */
  1018. /* ARGSUSED */
  1019. static void
  1020. counter_cb(FL_OBJECT * p, long q)
  1021. {
  1022.     double x = fl_get_counter_value(xcnt);
  1023.     double y = fl_get_counter_value(ycnt);
  1024.  
  1025.     if (showsize)
  1026.       {
  1027.       xscale = (xsize = x) / cw;
  1028.       yscale = (ysize = y) / ch;
  1029.       }
  1030.     else
  1031.       {
  1032.       xsize = ((xscale = x) * cw);
  1033.       ysize = ((yscale = y) * ch);
  1034.       }
  1035.  
  1036.     if (keepasp && !exact)
  1037.       {
  1038.       if (q == 1)
  1039.         {            /* x counter */
  1040.         yscale = xscale;
  1041.         }
  1042.       else
  1043.         {
  1044.         xscale = yscale;
  1045.         }
  1046.       xsize = xscale * cw;
  1047.       ysize = xscale * ch;
  1048.       }
  1049.     set_counter();
  1050. }
  1051.  
  1052. /******** Show fill color *******/
  1053.  
  1054. #define FILLCI  257        /* fill color form index  */
  1055.  
  1056. /* ARGSUSED */
  1057. extern IPTR imgptr;
  1058. static void
  1059. fill_cb(FL_OBJECT * ob, long q)
  1060. {
  1061.     /* block until satisfactory */
  1062.     get_color(imgptr, fillcol, 1);
  1063.  
  1064.     fl_mapcolor(FILLCI, fillcol[0], fillcol[1], fillcol[2]);
  1065.     fl_redraw_object(ob);
  1066. }
  1067.  
  1068. /* this two must not be 0, 1, 2 */
  1069. #define KEEPASP  10
  1070. #define EXACT   11
  1071.  
  1072. /* set options */
  1073. static void
  1074. misc_cb(FL_OBJECT * ob, long p)
  1075. {
  1076.     switch (p)
  1077.       {
  1078.       case KEEPASP:
  1079.       keepasp = fl_get_button(ob);
  1080.       break;
  1081.       case EXACT:
  1082.       if ((exact = fl_get_button(ob)))
  1083.         {            /* set change to 1pix */
  1084.         if (showsize)
  1085.           {
  1086.               fl_set_counter_step(xcnt, 1.0, 5 * minw);
  1087.               fl_set_counter_step(ycnt, 1.0, 5 * minw);
  1088.           }
  1089.         }
  1090.       break;
  1091.       default:
  1092.       subp = p;
  1093.       break;
  1094.       }
  1095. }
  1096.  
  1097. static void
  1098. create_form_fscale(void)
  1099. {
  1100.     FL_OBJECT *obj;
  1101.     static int ok;
  1102.  
  1103.     if (ok)
  1104.     return;
  1105.  
  1106.     fscale = fl_bgn_form(FL_UP_BOX, 250.0, 240.0);
  1107.     obj = fl_add_button(FL_HIDDEN_BUTTON, 0, 0, 250, 240, "");
  1108.     fl_set_call_back(obj, help_cb, HELP_SCALE);
  1109.     obj = fl_add_text(FL_NT, 30.0, 200.0, 205.0, 25.0, "RasterScale");
  1110.     fl_set_object_lcol(obj, 4);
  1111.     fl_set_object_lsize(obj, 16.000000);
  1112.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1113.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1114.  
  1115.     /* the x,y counters */
  1116.     xcnt = fl_add_counter(FL_NC, 50.0, 115.0, 160.0, 25.0, "X");
  1117.     fl_set_object_lcol(xcnt, 4);
  1118.     fl_set_object_lsize(xcnt, 10.0);
  1119.     fl_set_object_align(xcnt, FL_ALIGN_LEFT);
  1120.     fl_set_object_lstyle(xcnt, FL_BOLD_STYLE);
  1121.     fl_set_call_back(xcnt, counter_cb, 1);
  1122.  
  1123.     ycnt = fl_add_counter(FL_NC, 50.0, 90.0, 160.0, 25.0, "Y");
  1124.     fl_set_object_lcol(ycnt, 4);
  1125.     fl_set_object_lsize(ycnt, 10.0);
  1126.     fl_set_object_align(ycnt, FL_ALIGN_LEFT);
  1127.     fl_set_object_lstyle(ycnt, FL_BOLD_STYLE);
  1128.     fl_set_call_back(ycnt, counter_cb, 0);
  1129.  
  1130.     /* what to show */
  1131.     fl_bgn_group();
  1132.     obj = fl_add_roundbutton(FL_RB, 15.0, 50.0, 30.0, 30.0, "ShowSize");
  1133.     fl_set_object_lsize(obj, 10.0);
  1134.     fl_set_call_back(obj, show_size, 1);
  1135.     obj = fl_add_roundbutton(FL_RB, 130.0, 50.0, 30.0, 30.0, "ShowScale");
  1136.     fl_set_object_lsize(obj, 10.0);
  1137.     fl_set_button(obj, 1);
  1138.     fl_set_call_back(obj, show_size, 0);
  1139.     fl_end_group();
  1140.  
  1141.     /* misc settings */
  1142.  
  1143.     fl_bgn_group();
  1144.     ssubp[0] = fl_add_roundbutton(FL_RB, 10.0, 170.0, 30.0, 30.0, "NoAA");
  1145.     fl_set_object_lsize(ssubp[0], 10.000);
  1146.     fl_set_button(ssubp[0], (subp == 0));
  1147.     fl_set_call_back(ssubp[0], misc_cb, 0);
  1148.  
  1149.     ssubp[1] = fl_add_roundbutton(FL_RB, 90.0, 170.0, 30.0, 30.0, "FastAA");
  1150.     fl_set_object_lsize(ssubp[1], 10.000);
  1151.     fl_set_button(ssubp[1], (subp == 1));
  1152.     fl_set_call_back(ssubp[1], misc_cb, 1);
  1153.  
  1154.     ssubp[2] = fl_add_roundbutton(FL_RB, 170.0, 170.0, 30.0, 30.0, "Hi-Fi");
  1155.     fl_set_object_lsize(ssubp[2], 10.000);
  1156.     fl_set_button(ssubp[2], (subp == 2));
  1157.     fl_set_call_back(ssubp[2], misc_cb, 2);
  1158.     fl_end_group();
  1159.  
  1160.     obj = fl_add_roundbutton(FL_PB, 10.0, 145.0, 30.0, 30.0, "KeepASP");
  1161.     fl_set_object_lsize(obj, 10.0);
  1162.     fl_set_button(obj, keepasp);
  1163.     fl_set_call_back(obj, misc_cb, KEEPASP);
  1164.  
  1165.     obj = fl_add_roundbutton(FL_PB, 90.0, 145.0, 30.0, 30.0, "Exact");
  1166.     fl_set_object_lsize(obj, 10.0);
  1167.     fl_set_button(obj, exact);
  1168.     fl_set_call_back(obj, misc_cb, EXACT);
  1169.  
  1170.     /* control buttons */
  1171.     scaledone = obj = fl_add_button(FL_NB, 100.0, 10.0, 65.0, 25.0, "Done");
  1172.     fl_set_object_color(obj, 47, 3);
  1173.     fl_set_object_lsize(obj, 10.0);
  1174.     scaleit = obj = fl_add_button(FL_NB, 165.0, 10.0, 65.0, 25.0, "OK");
  1175.     fl_set_object_color(obj, 47, 2);
  1176.     fl_set_object_lsize(obj, 10.0);
  1177.  
  1178.     obj = fl_add_button(FL_NB, 40.0, 10.0, 60.0, 25.0, "FillColor");
  1179.     fl_set_object_color(obj, FILLCI, FL_BLUE);
  1180.     fl_set_object_lcol(obj, FL_MAGENTA);
  1181.     fl_set_object_lsize(obj, 10.0);
  1182.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1183.     fl_mapcolor(FILLCI, fillcol[0], fillcol[1], fillcol[2]);
  1184.     fl_set_call_back(obj, fill_cb, 0);
  1185.     fl_end_form();
  1186.     ok = 1;
  1187. }
  1188.  
  1189. /******************************************************************
  1190.  * END of Scaling
  1191.  ***************************************************************}*/
  1192.  
  1193. /***************************************************************
  1194.  * Rotation
  1195.  *************************************************************/
  1196. #include <math.h>
  1197. static int iangle = 90;        /* rotation angle         */
  1198. static int aaopt = 1;        /* weather anti-aliasing  */
  1199. static int lc[4];        /* fill color             */
  1200.  
  1201.  
  1202. /*********************************************************************
  1203.  * rotate an image by 90 or -90 or multiples of it. Rotate 180
  1204.  * could've been done in place by rotatematrix.
  1205.  *******************************************************************/
  1206. static int
  1207. image_rot_special(IPTR im, int deg)
  1208. {
  1209.     void *p;
  1210.     int oh = im->h, ow = im->w;
  1211.  
  1212.     show_busy("Rotating ...");
  1213.     p = rotate_mat(im->mraster, oh, ow, deg, im->esize);
  1214.     end_busy();
  1215.     if (!p)
  1216.     return -1;
  1217.     return (deg == 90 || deg == -90) ?
  1218.     fill_image_struct(im, p, ow, oh, im->type) :
  1219.     fill_image_struct(im, p, oh, ow, im->type);
  1220. }
  1221.  
  1222. /*************************************************
  1223.  * Mirrors. dir= 0: X-mirror, dir=1 Y-mirror
  1224.  *************************************************/
  1225. static int
  1226. image_mirror(IPTR im, int dir)
  1227. {
  1228.     int p;;
  1229.     if ((p = flip_mat(im->mraster, im->h, im->w, dir, im->esize) >= 0))
  1230.     im->io->display(im, -1, 0);
  1231.     return p ? 0 : -1;
  1232. }
  1233.  
  1234. /**************************************************************
  1235.  * Rotation routine dispatcher
  1236.  *************************************************************/
  1237.  
  1238. static int
  1239. ras_rotate(IPTR im, int angle, int aa, rgba_t fill)
  1240. {
  1241.     float pi = acos(-1.0), fa, absin;
  1242.     double sina, cosa, xoff, yoff;
  1243.     float tmat[2][2], shift[2];
  1244.     int nw, nh, h, w, status = 0;
  1245.  
  1246.     /* normalize to within (-180,180) */
  1247.     while (angle < -180)
  1248.     angle += 360;
  1249.     while (angle > 180)
  1250.     angle -= 360;
  1251.  
  1252.     /* check for special angles first */
  1253.     iangle = angle;
  1254.  
  1255.     /* normalize the angle between  (-90,90). Flip if neccessary */
  1256.     if (angle == 180 || angle == -180)
  1257.       {
  1258.       angle = 0;
  1259.       status = image_rot_special(im, 180);
  1260.       }
  1261.     else if (angle >= 90)
  1262.       {
  1263.       angle -= 90;
  1264.       status = image_rot_special(im, 90);
  1265.       }
  1266.     else if (angle <= -90)
  1267.       {
  1268.       angle += 90;
  1269.       status = image_rot_special(im, -90);
  1270.       }
  1271.     if (status < 0)
  1272.       {
  1273.       Bark("RotateSpecial", "Something is wrong");
  1274.       return -1;
  1275.       }
  1276.     if (angle == 0)
  1277.       {
  1278.       im->io->display(im, -1, 0);
  1279.       return 0;
  1280.       }
  1281.  
  1282.     /* following code assumed that the angle is between (-90,90) */
  1283.     w = im->w;
  1284.     h = im->h;
  1285.     iangle = angle;
  1286.     fa = angle * pi / 180.0;
  1287.     cosa = cos(fa);
  1288.     sina = sin(fa);
  1289.     absin = sina > 0.0 ? sina : -sina;
  1290.  
  1291.     nw = (cosa * w + absin * h + 1.9999);
  1292.     nh = (cosa * h + absin * w + 1.9999);
  1293.     update_size_info(nw, nh);
  1294.  
  1295.     if (angle > 0)
  1296.       {
  1297.       xoff = absin * h;
  1298.       yoff = 0;
  1299.       }
  1300.     else
  1301.       {
  1302.       xoff = 0;
  1303.       yoff = absin * w;
  1304.       }
  1305.  
  1306.     /**********************************************
  1307.      * /                         \
  1308.      * | cos(theta)  sin(theta)  |
  1309.      * |-sin(theta)  cos(theta)  |
  1310.      * \                         /
  1311.      ***********************************************/
  1312.  
  1313.     tmat[0][0] = tmat[1][1] = cosa;
  1314.     tmat[0][1] = sina;
  1315.     tmat[1][0] = -tmat[0][1];
  1316.  
  1317.     shift[0] = (xoff + 0.99);
  1318.     shift[1] = (yoff + 0.99);
  1319.  
  1320.     if ((status = img_tran(im, nh, nw, tmat, shift, fill, aa)) >= 0)
  1321.     im->io->display(im, -1, 0);
  1322.     return status;
  1323. }
  1324.  
  1325. /********************************************************
  1326.  * GUI part of rotation
  1327.  *******************************************************/
  1328. static FL_FORM *rrot;
  1329. static FL_OBJECT *done, *doit, *rptext;
  1330.  
  1331. #define XMIRROR   900
  1332. #define YMIRROR   1800
  1333.  
  1334. static void create_form_rrot(void);
  1335.  
  1336. /**************************************************************
  1337.  * Global entry point for rotation
  1338.  *************************************************************/
  1339. int
  1340. do_rotate(IPTR im)
  1341. {
  1342.     FL_OBJECT *ret;
  1343.     short val;
  1344.     int changed = 0;
  1345.  
  1346.     create_form_rrot();
  1347.     deactivate_all_forms();
  1348.  
  1349.     bit_show_form(rrot, FL_PLACE_MOUSE, 0, "Rotate");
  1350.  
  1351.     while ((ret = fl_do_forms()) != done)
  1352.       {
  1353.       if (ret == doit && iangle != 0)
  1354.         {
  1355.         changed = 1;
  1356.         if (iangle == XMIRROR)
  1357.           {
  1358.               image_mirror(im, 'x');
  1359.           }
  1360.         else if (iangle == YMIRROR)
  1361.           {
  1362.               image_mirror(im, 'y');
  1363.           }
  1364.         else
  1365.           {
  1366.               ras_rotate(im, iangle, aaopt, IS_CI(im) ?
  1367.                  lc[3] : Pack(lc[0], lc[1], lc[2]));
  1368.           }
  1369.         }
  1370.       else if (ret == FL_EVENT)
  1371.           (void) bit_qread(&val);
  1372.       }
  1373.     fl_activate_all_forms();
  1374.     bit_hide_form(rrot);
  1375.     return changed ? 0 : -1;
  1376. }
  1377.  
  1378. /* ARGSUSED */
  1379. static void
  1380. set_opt(FL_OBJECT * a, long p)
  1381. {
  1382.     aaopt = p;
  1383. }
  1384.  
  1385.  
  1386. #define LSTEP_  10
  1387. #define SSTEP_   1
  1388. /* ARGSUSED */
  1389. static void
  1390. set_angle(FL_OBJECT * a, long p)
  1391. {
  1392.     char sreport[50];
  1393.     static int langle;
  1394.  
  1395.     if (iangle > 360)
  1396.     iangle = langle;
  1397.     switch (p)
  1398.       {
  1399.       case 66:
  1400.       iangle += LSTEP_;
  1401.       break;
  1402.       case 6:
  1403.       iangle += SSTEP_;
  1404.       break;
  1405.       case 44:
  1406.       iangle -= LSTEP_;
  1407.       break;
  1408.       case 4:
  1409.       iangle -= SSTEP_;
  1410.       break;
  1411.       }
  1412.  
  1413.     if (iangle > 180)
  1414.     iangle -= 360;
  1415.     else if (iangle < -180)
  1416.     iangle += 360;
  1417.     sprintf(sreport, "%d", iangle);
  1418.  
  1419.     langle = iangle;
  1420.     fl_set_object_label(rptext, sreport);
  1421. }
  1422.  
  1423. /*********** Show fill color ***********************/
  1424. #define RFILLCI  258        /* fill color form index  */
  1425. /* ARGSUSED */
  1426. static void
  1427. set_fill(FL_OBJECT * ob, long p)
  1428. {
  1429.     get_color(imgptr, lc, 1);    /* block */
  1430.  
  1431.     fl_mapcolor(RFILLCI, lc[0], lc[1], lc[2]);
  1432.     fl_redraw_object(ob);
  1433. }
  1434.  
  1435.  
  1436. /* ARGSUSED */
  1437. static void
  1438. set_mirror(FL_OBJECT * a, long p)
  1439. {
  1440.     const char *rp = 0;
  1441.  
  1442.     iangle = p;
  1443.     if (p == XMIRROR)
  1444.       {
  1445.       rp = "Flip about X";
  1446.       }
  1447.     else if (p == YMIRROR)
  1448.       {
  1449.       rp = "Flip about Y";
  1450.       }
  1451.     else if (p == 90)
  1452.       {
  1453.       rp = "90";
  1454.       }
  1455.     else if (p == -90)
  1456.       {
  1457.       rp = "-90";
  1458.       }
  1459.     else if (p == 180)
  1460.       {
  1461.       rp = "180";
  1462.       }
  1463.     fl_set_object_label(rptext, rp);
  1464. }
  1465.  
  1466. static void
  1467. create_form_rrot(void)
  1468. {
  1469.     FL_OBJECT *obj;
  1470.     static int ok;
  1471.  
  1472.     if (ok)
  1473.     return;
  1474.  
  1475.     rrot = fl_bgn_form(FL_NO_BOX, 245.0, 250.0);
  1476.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 245.0, 250.0, "");
  1477.     fl_set_object_color(obj, 9, 47);
  1478.     obj = fl_add_button(FL_HB, 0.0, 0.0, 245, 245, "");
  1479.     fl_set_call_back(obj, help_cb, HELP_ROTATE);
  1480.  
  1481.     obj = fl_add_text(FL_NT, 30.0, 210.0, 195.0, 25.0, "RasterRotation");
  1482.     fl_set_object_lcol(obj, 4);
  1483.     fl_set_object_lsize(obj, 12.00);
  1484.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1485.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1486.  
  1487.     /* control */
  1488.     done = obj = fl_add_button(FL_NB, 85.0, 10.0, 70.0, 25.0, "Done");
  1489.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1490.     fl_set_object_color(obj, 47, 3);
  1491.     fl_set_object_lsize(obj, 10.0);
  1492.     doit = obj = fl_add_button(FL_NB, 155.0, 10.0, 75.0, 25.0, "OK");
  1493.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1494.     fl_set_object_color(obj, 47, 2);
  1495.     fl_set_object_lsize(obj, 10.0);
  1496.  
  1497.  
  1498.     /* option group */
  1499.     fl_bgn_group();
  1500.     obj = fl_add_roundbutton(FL_RB, 10.0, 45.0, 30.0, 30.0, "no anti-aliasing");
  1501.     fl_set_object_color(obj, 7, 1);
  1502.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  1503.     fl_set_call_back(obj, set_opt, 0);
  1504.     obj = fl_add_roundbutton(FL_RB, 105.0, 45.0, 30.0, 30.0, "Anit-aliasing");
  1505.     fl_set_object_color(obj, 7, 1);
  1506.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  1507.     fl_set_button(obj, 1);
  1508.     fl_set_call_back(obj, set_opt, 1);
  1509.     obj = fl_add_roundbutton(FL_RB, 190.0, 45.0, 30.0, 30.0, "hi-fi");
  1510.     fl_set_object_color(obj, 7, 1);
  1511.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  1512.     fl_set_call_back(obj, set_opt, 2);
  1513.     fl_end_group();
  1514.  
  1515.     /* mirror and misc groups */
  1516.     obj = fl_add_button(FL_NB, 20.0, 170.0, 70.0, 25.0, "X-mirror");
  1517.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1518.     fl_set_object_color(obj, 47, 3);
  1519.     fl_set_object_lsize(obj, 10.0);
  1520.     fl_set_call_back(obj, set_mirror, XMIRROR);
  1521.     obj = fl_add_button(FL_NB, 90.0, 170.0, 70.0, 25.0, "Y-mirror");
  1522.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1523.     fl_set_object_color(obj, 47, 3);
  1524.     fl_set_object_lsize(obj, 10.0);
  1525.     fl_set_call_back(obj, set_mirror, YMIRROR);
  1526.     obj = fl_add_button(FL_NB, 160.0, 170.0, 70.0, 25.0, "180");
  1527.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1528.     fl_set_object_color(obj, 47, 3);
  1529.     fl_set_object_lsize(obj, 10.0);
  1530.     fl_set_call_back(obj, set_mirror, 180);
  1531.     obj = fl_add_button(FL_NB, 20.0, 145.0, 70.0, 25.0, "+90");
  1532.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1533.     fl_set_object_color(obj, 47, 3);
  1534.     fl_set_object_lsize(obj, 10.0);
  1535.     fl_set_call_back(obj, set_mirror, 90);
  1536.     obj = fl_add_button(FL_NB, 90.0, 145.0, 70.0, 25.0, "-90");
  1537.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1538.     fl_set_object_color(obj, 47, 3);
  1539.     fl_set_object_lsize(obj, 10.0);
  1540.     fl_set_call_back(obj, set_mirror, -90);
  1541.  
  1542.     /* fill color stuff */
  1543.     obj = fl_add_button(FL_NB, 160.0, 145.0, 70.0, 25.0, "FillColor");
  1544.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1545.     fl_set_object_color(obj, RFILLCI, 3);
  1546.     fl_mapcolor(RFILLCI, lc[0], lc[1], lc[2]);
  1547.     fl_set_object_lsize(obj, 10.0);
  1548.     fl_set_object_lcol(obj, FL_MAGENTA);
  1549.     fl_set_call_back(obj, set_fill, 0);
  1550.  
  1551.     /* reporting */
  1552.     obj = fl_add_text(FL_NT, 60.0, 110.0, 130.0, 15.0, "Current Rotation");
  1553.     fl_set_object_lcol(obj, 4);
  1554.     fl_set_object_lsize(obj, 10.0);
  1555.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1556.     rptext = obj = fl_add_text(FL_NT, 85.0, 80.0, 75.0, 25.0, "90");
  1557.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1558.     fl_set_object_lcol(obj, 4);
  1559.     fl_set_object_lsize(obj, 10.0);
  1560.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1561.  
  1562.     /* Angle setting group */
  1563.     obj = fl_add_button(FL_TOUCH_BUTTON, 185.0, 80.0, 25.0, 25.0, ">>");
  1564.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1565.     fl_set_object_color(obj, 47, 9);
  1566.     fl_set_call_back(obj, set_angle, 66);
  1567.     obj = fl_add_button(FL_TOUCH_BUTTON, 160.0, 80.0, 25.0, 25.0, ">");
  1568.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1569.     fl_set_object_color(obj, 47, 9);
  1570.     fl_set_call_back(obj, set_angle, 6);
  1571.     obj = fl_add_button(FL_TOUCH_BUTTON, 60.0, 80.0, 25.0, 25.0, "<");
  1572.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1573.     fl_set_object_color(obj, 47, 9);
  1574.     fl_set_call_back(obj, set_angle, 4);
  1575.     obj = fl_add_button(FL_TOUCH_BUTTON, 35.0, 80.0, 25.0, 25.0, "<<");
  1576.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1577.     fl_set_object_color(obj, 47, 9);
  1578.     fl_set_call_back(obj, set_angle, 44);
  1579.     fl_end_form();
  1580.     ok = 1;
  1581. }
  1582.